//
//  CZChatViewController.m
//  XMPP项目练习
//
//  Created by 盛 发 况 on 16/5/5.
//  Copyright © 2016年 盛 发 况. All rights reserved.
//

#import "CZChatViewController.h"
#import "CZXMPPTools.h"
#import "CZChatCell.h"
#import "UIImage+Scale.h"
#import "CZRecorder.h"

@interface CZChatViewController ()<UITableViewDataSource,UITableViewDelegate,NSFetchedResultsControllerDelegate,UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;

@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;

/** 输入视图底部约束 */
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *inputViewBottomConstraint;

/** 输入视图的高度约束 */
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *inputViewHeightContraint;

/** 文本视图的高度约束 */
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewHeightContraint;

/** 录音文本 */
@property (nonatomic, strong) UITextField *recordText;
/** 输入视图 */
@property (weak, nonatomic) IBOutlet UIView *inputMessageView;

@end

@implementation CZChatViewController

- (NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPMessageArchiving_Message_CoreDataObject"];
    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"timestamp" ascending:YES];
    request.sortDescriptors = @[sort];
    
    // 每一个聊天界面，只关心聊天对象的消息
    request.predicate = [NSPredicate predicateWithFormat:@"bareJidStr = %@",self.chatJID.bare];
    
    NSManagedObjectContext *ctx = [CZXMPPTools sharedXMPPTools].xmppMessageArchivingCoreDataStorage.mainThreadManagedObjectContext;
    
    _fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request managedObjectContext:ctx sectionNameKeyPath:nil cacheName:nil];
    _fetchedResultsController.delegate = self;
    
    return _fetchedResultsController;
}
// 内容变化(接收到其他好友的/我发送的消息)的时候，会触发
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

    [self.tableView reloadData];
    [self scrollToBottom];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //设置tableView的背景图片
    self.tableView.backgroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"login_bg.jpg"]];
    
    DDLogInfo(@"%@", self.chatJID);
    [self.fetchedResultsController performFetch:NULL];
   
    self.automaticallyAdjustsScrollViewInsets = NO;
    [self scrollToBottom];
    
    // 监听键盘变化
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardChanged:) name:UIKeyboardWillChangeFrameNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardDidChanged) name:UIKeyboardDidChangeFrameNotification object:nil];
}

//- (void)viewWillAppear:(BOOL)animated {
//    [super viewWillAppear:animated];
//
//    self.navigationController.hidesBottomBarWhenPushed = YES;
//}

//让文本框停止编辑,收回键盘
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {

    [self.view endEditing:YES];
}


- (void)keyboardChanged:(NSNotification *)notification {

//    DDLogInfo(@"%@", notification);
//    // 使用自动布局，一旦约束设定合理，当界面变化的时候，只要修改少量的约束即可！
//    CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
//    self.inputViewBottomConstraint.constant = keyboardRect.size.height;
    
    
    // 获取动画的持续时间
    NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    // 获取键盘动画运行曲线(趋势)
    int curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue];
    CGRect keyboard_frame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    // 计算出本次要平移的值
    CGFloat keyboardY = keyboard_frame.origin.y;
    CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
    CGFloat offsetY = keyboardY - screenH;
    
    // 让控制器的view做相应的平移
    [UIView animateWithDuration:duration animations:^{
        
        [UIView setAnimationCurve:curve];
        self.view.transform = CGAffineTransformMakeTranslation(0, offsetY);
        
    }];
    
    // 让Table View最后一行滚动到最上面
//    NSIndexPath *idx_last = [NSIndexPath indexPathForRow:self.messages.count - 1 inSection:0];
//    [self.tableView scrollToRowAtIndexPath:idx_last atScrollPosition:UITableViewScrollPositionTop animated:YES];
    [self scrollToBottom];

}
- (void)keyboardDidChanged {

    [self scrollToBottom];
}

#pragma mark - UITextView代理方法
// 替换文字
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    
    NSDictionary *attr = @{NSFontAttributeName : [UIFont systemFontOfSize:20]};
    CGRect textRect = [textView.text boundingRectWithSize:CGSizeMake(textView.bounds.size.width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil];
    
    //超过一行才需要变化,够了三行就不变化
    if (textRect.size.height > 30 && textRect.size.height < 80) {
        self.textViewHeightContraint.constant = textRect.size.height;
        self.inputViewHeightContraint.constant = self.textViewHeightContraint.constant + 14;
    } else if(textRect.size.height < 30){
        self.textViewHeightContraint.constant = 30;
        self.inputViewHeightContraint.constant = self.textViewHeightContraint.constant + 14;
    }
    [self scrollToBottom];
    DDLogInfo(@"%@", text);
    
    // 拦截用户的回车
    if ([text isEqualToString:@"\n"]) {
        // 发送消息
        [self sendMsg:textView.text];
        textView.text = @"";
        
        self.textViewHeightContraint.constant = 30;
        self.inputViewHeightContraint.constant = self.textViewHeightContraint.constant + 14;
        
        return NO;
    }

    return YES;
}
// 发送文字消息
- (void)sendMsg:(NSString *)text {
    // 类型是聊天
    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatJID];
    [message addBody:text];
    
    // 发送消息
    [[CZXMPPTools sharedXMPPTools].xmppStream sendElement:message];
    
}

// 滚动到表格的末尾，显示最新的聊天内容
- (void)scrollToBottom {
    if (self.fetchedResultsController.fetchedObjects.count == 0) {
        return;
    }
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.fetchedResultsController.fetchedObjects.count - 1 inSection:0];
    
    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

#pragma mark - 选择图片
- (IBAction)selectPhoto {
    
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    
    picker.delegate = self;
    
    // 显示照片选择控制器
    [self presentViewController:picker animated:YES completion:nil];
    
}
#pragma mark - 照片查看器代理方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    
    UIImage *image = info[UIImagePickerControllerOriginalImage];

    NSData *data = UIImagePNGRepresentation(image);
    [self sendMessageWithData:data bodyName:@"image"];
    
    [self dismissViewControllerAnimated:YES completion:nil];
    
}
/** 发送二进制数据的消息 */
- (void)sendMessageWithData:(NSData *)data bodyName:(NSString *)bodyName {
    // 1. 实例化一个XMPPMesssage
    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatJID];
    
    // 2. 设置文本正文文字，只有一个image，注意不能在body中设置base64字符串，否则其他客户端会直接显示base64的字符串！
    [message addBody:bodyName];
    
    // 3. 将data当作消息"附件"
    // 1> base64编码转换成字符串
    NSString *base64Str = [data base64EncodedStringWithOptions:0];
    // 2> 实例化一个XML节点，添加到message的XML中
    /**
     参数：
     1. 节点名称
     2. 节点内容
     */
    XMPPElement *attachment = [XMPPElement elementWithName:@"attachment" stringValue:base64Str];
    
    // 将base64节点添加成message的子结点
    [message addChild:attachment];
    
    // 发送消息
    [[CZXMPPTools sharedXMPPTools].xmppStream sendElement:message];
}
#pragma mark - 录音部分
- (UITextField *)recordText {
    if (_recordText == nil) {
        _recordText = [[UITextField alloc] init];
        
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
        _recordText.inputView = btn;
        
        [btn addTarget:self action:@selector(startRecord) forControlEvents:UIControlEventTouchDown];
        [btn addTarget:self action:@selector(stopRecord) forControlEvents:UIControlEventTouchUpInside];
        
        [self.inputMessageView addSubview:_recordText];
    }
    return _recordText;
}

- (void)startRecord {
    NSLog(@"开始录音");
    [[CZRecorder sharedRecorder] startRecord];
}

- (void)stopRecord {
    NSLog(@"停止录音");
    [[CZRecorder sharedRecorder] stopRecordSuccess:^(NSURL *url, NSTimeInterval time) {
        // 拿到数据进行发送
        NSLog(@"%@", url.path);
        
        // 发送声音数据
        NSData *data = [NSData dataWithContentsOfURL:url];
        [self sendMessageWithData:data bodyName:[NSString stringWithFormat:@"audio:%.02f", time]];
    } faild:^{
        [[[UIAlertView alloc] initWithTitle:@"提示" message:@"时间太短" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show];
    }];
}

- (IBAction)clickRecord {
    
    // 切换焦点，弹出录音按钮
    [self.recordText becomeFirstResponder];
}

#pragma mark -- tableView的数据源及代理
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    return self.fetchedResultsController.fetchedObjects.count;
}

/**
 重构：
 1. 先将重复的代码复制到新的方法
 2. 根据需要调整方法参数
 3. 继续扩展之前，一定要测试，保证原有代码的修改是正确的！
 */
/** 取得指定indexPath的可重用Cell */
- (CZChatCell *)cellWithTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath{
    
    // 聊天记录的对象
    XMPPMessageArchiving_Message_CoreDataObject *message = [self.fetchedResultsController objectAtIndexPath:indexPath];
    
    // 根据message的outgoing来判断是发送还是接收
    NSString *ID = (message.isOutgoing) ? @"SendCell" : @"ReceiveCell";
    
    CZChatCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    // 清空音频数据
    cell.audioData = nil;
    
    // 判断是否是图片消息
    if ([message.body isEqualToString:@"image"]) {
        // 如果发送的是图片，cell中要显示的内容应该是图片，而不应该是body
        // 首先拿到message，从message中，得到发送消息时指定的"attachment"节点，attachment可以随便起名，注意不要冲突
        XMPPMessage *msg = message.message;
        // 2. 获得 attachment 节点
        NSLog(@"child %zd", msg.childCount);
        
        // 遍历msg的所有节点
        for (XMPPElement *node in msg.children) {
            // attachment 节点中的内容，就是base64之后的图片
            // 拿到 attachment 节点的内容
            NSString *base64Str = node.stringValue;
            
            // 使用base64字符串创建图片的二进制数据
            NSData *data = [[NSData alloc] initWithBase64EncodedString:base64Str options:0];
            
            // 将二进制数据转换成UIImage
            UIImage *image = [UIImage imageWithData:data];
            
            // 将图像设置给label => 图文混排
            // 1> 生成文本附件
            NSTextAttachment *textAttach = [[NSTextAttachment alloc] init];
            textAttach.image = [image scaleImageWithWidth:80];
            
            // 2> 使用文本附件创建属性文本
            NSAttributedString *strA = [NSAttributedString attributedStringWithAttachment:textAttach];
            
            cell.messageLabel.attributedText = strA;
        }
    } else if ([message.body hasPrefix:@"audio"]) {
        // 音频文件
        XMPPMessage *msg = message.message;
        // 2. 获得 attachment 节点
        NSLog(@"音频 child %zd", msg.childCount);
        
        for (XMPPElement *node in msg.children) {
            NSString *base64Str = node.stringValue;
            
            // 使用base64字符串创建音频数据
            NSData *data = [[NSData alloc] initWithBase64EncodedString:base64Str options:0];
            
            // cell的文字
            cell.messageLabel.text = message.body;
            // cell 记录音频数据
            cell.audioData = data;
        }
    } else {
        // 其他消息
        cell.messageLabel.text = message.body;
    }
    
    return cell;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    return [self cellWithTableView:tableView indexPath:indexPath];
}

#pragma mark - 表格代理方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    // 拿到Cell，设置数值
    CZChatCell *cell = [self cellWithTableView:tableView indexPath:indexPath];
    
    // 让cell自动布局
    [cell layoutIfNeeded];
    
    // 拿出cell中label自动布局之后的高度（24是顶边距和底边距的和）
    CGFloat height = [cell.messageLabel systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 40;
    
    if (height < 80) {
        height = 80;
    }
    
    return height;
}

// Cell预估高度
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 80;
}

//让选中行变成非选中
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    [self.tableView deselectRowAtIndexPath:indexPath animated:NO];
}

//移除通知
- (void)dealloc {
    
    [[NSNotificationCenter defaultCenter]removeObserver:self];
}

@end









